﻿using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using System;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace K3Cloud.WebApi.Core.IoC.K3Client
{
    public class K3HttpService(HttpClient httpClient, IOptions<K3Config> options) : IDisposable
    {
        public string BaseUrl { get; set; }
        public string Path { get; set; }
        public string? Content { get; set; }

        private readonly HttpClient _httpClient = httpClient;
        private readonly IOptions<K3Config> _options = options;

        public async Task<string> PostAsync(string serverUrl, string path, string? content = "", CancellationToken cancellationToken = default)
        {
            BaseUrl = serverUrl;
            Path = path;
            Content = content;
            return await PostAsync(cancellationToken);
        }
        public async Task<string> PostAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                JObject jObj = new()
                {
                    { "format", 1 },
                    { "useragent", "ApiClient" },
                    { "rid", Math.Abs(Guid.NewGuid().GetHashCode()) },
                    { "parameters", Content },
                    { "timestamp", DateTimeFormatUtils.CurrentTimeMillis() },
                    { "v", "1.0" }
                };
                HttpContent stringContent = new StringContent(jObj.ToString());
                stringContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                var result = await _httpClient.PostAsync(ResolveUrl(Path), stringContent, cancellationToken);
                result.EnsureSuccessStatusCode();
                return ValidateResult(await result.Content.ReadAsStringAsync());
            }
            catch (Exception ex)
            {
                throw new K3ApiException(ex.Message);
            }
        }

        public async Task<string> PostJsonAsync(string service_url, string sContent = "")
        {
            try
            {
                string path_url = service_url;
                if (service_url.StartsWith("http"))
                {
                    int p_index = service_url.IndexOf("/", 10);
                    if (p_index > -1)
                    {
#if NETSTANDARD2_1_OR_GREATER
                        path_url = service_url[p_index..];
#else
                        path_url = service_url.Substring(p_index);
#endif
                    }
                }
                path_url = path_url.Replace("/", "%2F");
                string[] arr = _options.Value.AppID.Split('_');
                string clientId = arr[0];
                string client_sec = KingdeeSignature.DecryptAppSecret(arr[1]);
                string timestamp = DateTimeFormatUtils.CurrentTimeSeconds().ToString();
                string nonce = timestamp;
                string api_sign = "POST\n" + path_url + "\n\nx-api-nonce:" + nonce + "\nx-api-timestamp:" + timestamp + "\n";
                string app_data = $"{_options.Value.AcctId},{_options.Value.UserName},{_options.Value.LCID},0";
                string api_signature = KingdeeSignature.HmacSHA256(api_sign, client_sec, Encoding.UTF8, true);
                string kd_signature = KingdeeSignature.HmacSHA256(_options.Value.AppID + app_data, _options.Value.AppSecret, Encoding.UTF8, true);
                _httpClient.DefaultRequestHeaders.Clear();
                _httpClient.DefaultRequestHeaders.Add("X-Api-ClientID", clientId);
                _httpClient.DefaultRequestHeaders.Add("X-Api-Auth-Version", "2.0");
                _httpClient.DefaultRequestHeaders.Add("x-api-timestamp", timestamp);
                _httpClient.DefaultRequestHeaders.Add("x-api-nonce", nonce);
                _httpClient.DefaultRequestHeaders.Add("x-api-signheaders", "x-api-timestamp,x-api-nonce");
                _httpClient.DefaultRequestHeaders.Add("X-Api-Signature", api_signature);
                _httpClient.DefaultRequestHeaders.Add("X-Kd-Appkey", _options.Value.AppID);
                _httpClient.DefaultRequestHeaders.Add("X-Kd-Appdata", Convert.ToBase64String(Encoding.UTF8.GetBytes(app_data)));
                _httpClient.DefaultRequestHeaders.Add("X-Kd-Signature", kd_signature);
                _httpClient.DefaultRequestHeaders.Add("Accept-Charset", "utf-8");
                _httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78");

                HttpContent stringContent = new StringContent(sContent);
                stringContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                HttpResponseMessage result = await _httpClient.PostAsync(service_url, stringContent);
                _ = result.EnsureSuccessStatusCode();
                return ValidateResult(await result.Content.ReadAsStringAsync());
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<string> GetAsync(string serverUrl, string path, CancellationToken cancellationToken = default)
        {
            BaseUrl = serverUrl;
            Path = path;
            return await GetAsync(cancellationToken);
        }
        public async Task<string> GetAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                var result = await _httpClient.GetAsync(ResolveUrl(Path), cancellationToken);
                result.EnsureSuccessStatusCode();
                return ValidateResult(await result.Content.ReadAsStringAsync());
            }
            catch (Exception)
            {
                throw;
            }
        }
        /// <summary>
        /// url拼接
        /// </summary>
        /// <returns></returns>
        private string ResolveUrl(string path)
        {
            if (path.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || path.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) { return path; }
            if (string.IsNullOrEmpty(BaseUrl)) { throw new ArgumentNullException(nameof(BaseUrl)); }
            string baseUrl = BaseUrl.TrimEnd('/');
            string fullUrl = path.StartsWith("/") ? baseUrl + path : $"{baseUrl}/{path}";
            return fullUrl;
        }
        private static string ValidateResult(string responseText)
        {
            return responseText.StartsWith("response_error:", StringComparison.OrdinalIgnoreCase)
                ? responseText.TrimStart("response_error:".ToCharArray())
                : responseText;
        }
        public void Dispose()
        {
            _httpClient.Dispose();
            GC.SuppressFinalize(this);
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
}
